// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UpDownSliderBase.cs" company="Roman '4ux-nbIx' Novitsky">
//   Copyright (c) Roman '4ux-nbIx' Novitsky 2010
// </copyright>
// <summary>
//   Defines the UpDownSliderBase type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace MtgMC
{
    #region Namespace Imports

    using System;
    using System.Drawing;
    using System.Windows.Forms;

    #endregion


    /// <summary>
    /// Implements the basic functionality common to up down slider controls.
    /// </summary>
    /// <typeparam name="T">
    /// The type of the value.
    /// </typeparam>
    public abstract class UpDownSliderBase<T> : Control
    {
        #region Constants and Fields

        private T _maxValue;
        private T _minValue;
        private int _padding = 1;
        private int _slideDistance = 20;
        private Color _thumbsBackgroundColor = SystemColors.Control;
        private Color _thumbsDownColor = SystemColors.ControlDark;
        private int _thumbsPadding = 1;
        private T _value;

        #endregion


        #region Events

        /// <summary>
        /// Occurs when the Value has changed.
        /// </summary>
        public event EventHandler<UpDownSliderEventArgs<T>> ValueChanged;

        /// <summary>
        /// Occurs when the Value has decreased.
        /// </summary>
        public event EventHandler<UpDownSliderEventArgs<T>> ValueDecreased;

        /// <summary>
        /// Occurs when the Value has increased.
        /// </summary>
        public event EventHandler<UpDownSliderEventArgs<T>> ValueIncreased;

        #endregion


        #region Properties

        /// <summary>
        /// Gets or sets the max value.
        /// </summary>
        /// <value>
        /// The max value.
        /// </value>
        public T MaxValue
        {
            get
            {
                return _maxValue;
            }

            set
            {
                _maxValue = value;

                OnMaxValueChanged();
            }
        }


        /// <summary>
        /// Gets or sets the min value.
        /// </summary>
        /// <value>
        /// The min value.
        /// </value>
        public T MinValue
        {
            get
            {
                return _minValue;
            }

            set
            {
                _minValue = value;

                OnMinValueChanged();
            }
        }

        /// <summary>
        /// Gets or sets the padding.
        /// </summary>
        /// <value>
        /// The padding.
        /// </value>
        public int Padding
        {
            get
            {
                return _padding;
            }

            set
            {
                _padding = value;

                OnPaddingChanged();
            }
        }


        /// <summary>
        /// Gets or sets the slide distance.
        /// </summary>
        /// <value>
        /// The slide distance.
        /// </value>
        public int SlideDistance
        {
            get
            {
                return _slideDistance;
            }

            set
            {
                _slideDistance = value;

                OnSlideLengthChanged();
            }
        }

        /// <summary>
        /// Gets or sets the color of the thumbs background.
        /// </summary>
        /// <value>
        /// The color of the thumbs background.
        /// </value>
        public Color ThumbsBackgroundColor
        {
            get
            {
                return _thumbsBackgroundColor;
            }

            set
            {
                _thumbsBackgroundColor = value;

                OnThumbsBackgroundColorChanged();
            }
        }

        /// <summary>
        /// Gets or sets the color of pressed thumbs.
        /// </summary>
        /// <value>
        /// The color of pressed thumbs.
        /// </value>
        public Color ThumbsDownColor
        {
            get
            {
                return _thumbsDownColor;
            }

            set
            {
                _thumbsDownColor = value;

                OnThumbsDownColorChanged();
            }
        }

        /// <summary>
        /// Gets or sets the thumbs padding.
        /// </summary>
        /// <value>
        /// The thumbs padding.
        /// </value>
        public int ThumbsPadding
        {
            get
            {
                return _thumbsPadding;
            }

            set
            {
                _thumbsPadding = value;

                OnThumbsPaddingChanged();
            }
        }


        /// <summary>
        /// Gets or sets the value.
        /// </summary>
        /// <value>
        /// The value.
        /// </value>
        public T Value
        {
            get
            {
                return _value;
            }

            set
            {
                T previousValue = _value;
                T newValue = ValidateValue(value);

                _value = newValue;

                if (ValueChanged != null)
                {
                    ValueChanged(this, new UpDownSliderEventArgs<T>(previousValue, _value, default(T)));
                }

                OnValueChanged();
            }
        }

        #endregion


        #region Public Methods

        /// <summary>
        /// Decreases the value.
        /// </summary>
        /// <param name="amount">
        /// The amount the value would be decreased.
        /// </param>
        public void DecreaseValue(T amount)
        {
            T previousValue = _value;
            T newValue = Subtract(_value, amount);

            newValue = ValidateValue(newValue);
            Value = newValue;

            if (ValueDecreased != null)
            {
                ValueDecreased(this, new UpDownSliderEventArgs<T>(previousValue, newValue, amount));
            }
        }


        /// <summary>
        /// Increases the value.
        /// </summary>
        /// <param name="amount">
        /// The amount the value would be increased.
        /// </param>
        public void IncreaseValue(T amount)
        {
            T previousValue = _value;
            T newValue = Add(_value, amount);

            newValue = ValidateValue(newValue);
            Value = newValue;

            if (ValueIncreased != null)
            {
                ValueIncreased(this, new UpDownSliderEventArgs<T>(previousValue, newValue, amount));
            }
        }

        #endregion


        #region Methods

        /// <summary>
        /// Adds the specified amount to the value.
        /// </summary>
        /// <param name="value">
        /// The value.
        /// </param>
        /// <param name="amount">
        /// The amount to add.
        /// </param>
        /// <returns>
        /// A new value.
        /// </returns>
        protected abstract T Add(T value, T amount);


        /// <summary>
        /// Determines whether the specified value1 is greater then value2.
        /// </summary>
        /// <param name="value1">
        /// The value1.
        /// </param>
        /// <param name="value2">
        /// The value2.
        /// </param>
        /// <returns>
        /// <c>true</c> if the specified value1 is greater then value2; otherwise, <c>false</c>.
        /// </returns>
        protected abstract bool IsGreater(T value1, T value2);


        /// <summary>
        /// Determines whether the specified value1 is lower then value2.
        /// </summary>
        /// <param name="value1">
        /// The value1.
        /// </param>
        /// <param name="value2">
        /// The value2.
        /// </param>
        /// <returns>
        /// <c>true</c> if the specified value1 is lower then value2; otherwise, <c>false</c>.
        /// </returns>
        protected abstract bool IsLower(T value1, T value2);


        /// <summary>
        /// Called when max value has changed.
        /// </summary>
        protected virtual void OnMaxValueChanged()
        {
        }


        /// <summary>
        /// Called when min value has changed.
        /// </summary>
        protected virtual void OnMinValueChanged()
        {
        }


        /// <summary>
        /// Called when padding has changed.
        /// </summary>
        protected virtual void OnPaddingChanged()
        {
        }


        /// <summary>
        /// Called when slide length has changed.
        /// </summary>
        protected virtual void OnSlideLengthChanged()
        {
        }


        /// <summary>
        /// Called when thumbs background color has changed.
        /// </summary>
        protected virtual void OnThumbsBackgroundColorChanged()
        {
        }


        /// <summary>
        /// Called when thumbs down color has changed.
        /// </summary>
        protected virtual void OnThumbsDownColorChanged()
        {
        }


        /// <summary>
        /// Called when thumbs padding has changed.
        /// </summary>
        protected virtual void OnThumbsPaddingChanged()
        {
        }


        /// <summary>
        /// Called when value has changed.
        /// </summary>
        protected virtual void OnValueChanged()
        {
        }


        /// <summary>
        /// Subtracts the specified amount from the value.
        /// </summary>
        /// <param name="value">
        /// The value.
        /// </param>
        /// <param name="amount">
        /// The amount to subtract.
        /// </param>
        /// <returns>
        /// New value.
        /// </returns>
        protected abstract T Subtract(T value, T amount);


        /// <summary>
        /// Validates the value.
        /// </summary>
        /// <param name="value">
        /// The value to validate.
        /// </param>
        /// <returns>
        /// Returns a valid value.
        /// </returns>
        private T ValidateValue(T value)
        {
            if (IsGreater(value, MaxValue))
            {
                value = MaxValue;
            }

            if (IsLower(value, MinValue))
            {
                value = MinValue;
            }

            return value;
        }

        #endregion
    }
}